﻿using System;
using System.Collections.Generic;
using System.Text;
using MyLibrary;

namespace MyLibrary.Net
{
    public enum MessageBlockType
    {
        /// <summary> 握手 </summary>
        Handshake = 1,
        /// <summary> 接收信号 </summary>
        AppData = 2,
        /// <summary> 警告 </summary>
        Alert = 3,
        /// <summary> 关闭通知 </summary>
        CloseNotify = 4,
        /// <summary> 心跳信号 </summary>
        HeartBeat = 5
    }

    /// <summary>
    /// 消息块类
    /// </summary>
    public class MessageBlock
    {
        private DataBlock _body;
        /// <summary>
        /// 消息体
        /// </summary>
        public DataBlock MessageBody
        {
            get { return _body; }
            set
            {
                if (value == null) throw new ArgumentNullException();
                _body = value;
                _bodyLength = value.DataLength;
            }
        }
        private DataBlock _head;
        /// <summary>
        /// 消息头
        /// </summary>
        public DataBlock MessageHead
        {
            get { return _head; }
            set { _head = value; }
        }
        private MessageBlockType _type;
        /// <summary>
        /// 消息类型
        /// </summary>
        public MessageBlockType MessageType
        {
            get { return _type; }
            set { _type = value; }
        }
        public const int _headLength = 16;
        int _bodyLength;
        /// <summary>
        /// 消息体长度
        /// </summary>
        public int BodyLength
        {
            get { return _bodyLength; }
        }
        int _parameter;
        /// <summary>
        /// 消息参数
        /// </summary>
        public int Parameter
        {
            get { return _parameter; }
            set { _parameter = value; }
        }
        /// <summary>
        /// 消息的总长度
        /// </summary>
        public int MessageLength
        {
            get { return _headLength + BodyLength; }
        }

        /// <summary>
        /// 构建空消息块
        /// </summary>
        public MessageBlock()
        {
            _head = new DataBlock(_headLength);
        }

        public MessageBlock(Byte[] data)
            : this(data, 0, data.Length)
        {

        }

        public MessageBlock(Byte[] data, int startIndex, int length)
            : this(new DataBlock(data, startIndex, length))
        {
        }

        public MessageBlock(DataBlock body)
            : this(MessageBlockType.AppData, 0, body)
        {
        }

        public MessageBlock(MessageBlockType type)
            : this(type, 0, null)
        {

        }

        public MessageBlock(MessageBlockType type, int parameter)
            : this(type, parameter, null)
        {
        }

        public MessageBlock(MessageBlockType type, int parameter, DataBlock body)
            : this()
        {
            MessageType = type;
            Parameter = parameter;
            if (body != null)
                MessageBody = body;
            CreateHead();
        }

        public DataBlock ToDataBlock()
        {
            return MessageHead + MessageBody;
        }

        /// <summary>
        /// 根据消息设置生成报文头
        /// </summary>
        public void CreateHead()
        {
            if (MessageHead == null || MessageHead.Buffer == null)
                MessageHead = new DataBlock(_headLength);
            byte[] result = this._head.Buffer;
            byte[] lengthBytes = ConvertPlus.ToBytes(MessageLength);
            byte[] typeBytes = ConvertPlus.ToBytes((int)MessageType);
            byte[] parameterBytes = ConvertPlus.ToBytes(Parameter);

            int index = 0;
            //添加长度信息
            Array.Copy(lengthBytes, 0, result, index, 4);
            index += 4;
            //添加类型信息
            Array.Copy(typeBytes, 0, result, index, 4);
            index += 4;
            //添加参数信息
            Array.Copy(parameterBytes, 0, result, index, 4);

            //扩展4位
            index += 4;
            this.MessageHead.WriteIndex = _headLength;
        }

        /// <summary>
        /// 从数据得到一个消息
        /// </summary>
        /// <param name="data">包含消息的数据</param>
        /// <param name="getHeadData">是否含有消息头</param>
        /// <param name="maxBodyLength">最大消息体长度</param>
        public void FromBytes(byte[] data, bool getHeadData, int maxBodyLength)
        {
            int index = 0;
            int length = (int)ConvertPlus.ToUInt32(data, index);
            this._bodyLength = length - _headLength;

            if (_bodyLength > maxBodyLength)
                throw new NetException(String.Format("Message is too Large {0}/{1}", _bodyLength, maxBodyLength));

            index += 4;
            MessageType = (MessageBlockType)ConvertPlus.ToUInt32(data, index);
            index += 4;
            Parameter = (int)ConvertPlus.ToUInt32(data, index);
            if (!getHeadData && length > _headLength)
            {
                index += 4;
                this._body = new DataBlock(length - _headLength);
                Array.Copy(data, index, _body.Buffer, _body.WriteIndex, _body.WriteableLength);
                _body.WriteIndex += _body.WriteableLength;
            }
            else if (BodyLength >= 0)
                _body = new DataBlock(length - _headLength);
            else throw new NetException("Bad Message Block Head Data");
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Length:");
            sb.Append(_headLength);
            sb.Append("+");
            sb.Append(BodyLength);
            sb.Append("\tType:");
            sb.Append(MessageType.ToString());
            sb.Append("\tPara:");
            switch (MessageType)
            {
                case MessageBlockType.Handshake:
                    break;
            }
            return sb.ToString();
        }

        public void CreateBodyByHead(int maxBodyLength)
        {
            FromBytes(MessageHead.Buffer, true, maxBodyLength);
        }
    }
}
